package com.springboot.file.util;

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.apache.poi.util.Units;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;

import java.io.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.concurrent.Future;

// Add imports for documents4j
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;

/**
 * 文档处理工具类
 * 提供Word文档和PDF文件操作的通用方法
 */
public class DocumentUtil {
    private static final Logger log = LoggerFactory.getLogger(DocumentUtil.class);
    private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");

    // 添加转换方法常量
    private static final String CONVERT_METHOD_LIBREOFFICE = "libreoffice";
    private static final String CONVERT_METHOD_OPENOFFICE = "openoffice";
    private static final String CONVERT_METHOD_MSOFFICE = "msoffice";
    private static final String CONVERT_METHOD_JAVA = "java";
    private static final String CONVERT_METHOD_DOCUMENTS4J = "documents4j";

    /**
     * 替换Word文档中的文本占位符
     *
     * @param template Word模板文件
     * @param data 替换数据
     * @return 替换后的Word文档
     */
    public static XWPFDocument replaceTextPlaceholders(XWPFDocument template, Map<String, Object> data) {
        if (data == null || data.isEmpty()) {
            return template;
        }

        // 替换段落中的占位符
        List<XWPFParagraph> paragraphs = template.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            List<XWPFRun> runs = paragraph.getRuns();
            for (int i = 0; i < runs.size(); i++) {
                String text = runs.get(i).getText(0);
                if (text != null) {
                    text = replacePlaceholdersInText(text, data);
                    runs.get(i).setText(text, 0);
                }
            }
        }

        // 替换表格中的占位符
        List<XWPFTable> tables = template.getTables();
        for (XWPFTable table : tables) {
            List<XWPFTableRow> rows = table.getRows();
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
                    for (XWPFParagraph cellParagraph : cellParagraphs) {
                        List<XWPFRun> cellRuns = cellParagraph.getRuns();
                        for (int i = 0; i < cellRuns.size(); i++) {
                            String text = cellRuns.get(i).getText(0);
                            if (text != null) {
                                text = replacePlaceholdersInText(text, data);
                                cellRuns.get(i).setText(text, 0);
                            }
                        }
                    }
                }
            }
        }

        return template;
    }

    /**
     * 替换文本中的占位符
     *
     * @param text 原始文本
     * @param data 替换数据
     * @return 替换后的文本
     */
    private static String replacePlaceholdersInText(String text, Map<String, Object> data) {
        if (text == null || text.isEmpty()) {
            return text;
        }

        Matcher matcher = PLACEHOLDER_PATTERN.matcher(text);
        StringBuilder result = new StringBuilder();
        int lastEnd = 0;

        while (matcher.find()) {
            result.append(text, lastEnd, matcher.start());
            String key = matcher.group(1);
            Object value = data.get(key);
            result.append(value != null ? value.toString() : matcher.group(0));
            lastEnd = matcher.end();
        }

        if (lastEnd < text.length()) {
            result.append(text.substring(lastEnd));
        }

        return result.toString();
    }

    /**
     * 添加页眉
     *
     * @param document Word文档对象
     * @param headerText 页眉文本
     */
    public static void addHeader(XWPFDocument document, String headerText) {
        if (headerText == null || headerText.isEmpty()) {
            return;
        }

        // 创建HeaderFooterPolicy
        XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(document);
        // 创建页眉
        XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
        XWPFParagraph paragraph = header.createParagraph();
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun run = paragraph.createRun();
        run.setText(headerText);
        run.setFontSize(10);
    }

    /**
     * 添加页脚
     *
     * @param document Word文档对象
     * @param footerText 页脚文本
     * @param showPageNumbers 是否显示页码
     */
    public static void addFooter(XWPFDocument document, String footerText, boolean showPageNumbers) {
        // 创建HeaderFooterPolicy
        XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(document);
        // 创建页脚
        XWPFFooter footer = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT);
        XWPFParagraph paragraph = footer.createParagraph();
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        
        if (footerText != null && !footerText.isEmpty()) {
            XWPFRun textRun = paragraph.createRun();
            textRun.setText(footerText);
            textRun.setFontSize(9);
            textRun.addBreak();
        }

        if (showPageNumbers) {
            // 更简单的页码实现
            XWPFRun run = paragraph.createRun();
            run.setText("页码: ");
            run.setFontSize(9);
            
            // 创建带页码的段落
            XWPFParagraph pageNumberParagraph = footer.createParagraph();
            pageNumberParagraph.setAlignment(ParagraphAlignment.CENTER);
            pageNumberParagraph.getCTP().addNewFldSimple().setInstr("PAGE \\* MERGEFORMAT");
        }
    }

    /**
     * 添加水印
     *
     * @param document Word文档对象
     * @param watermarkText 水印文本
     * @param color 水印颜色（格式如 #CCCCCC）
     */
    public static void addWatermark(XWPFDocument document, String watermarkText, String color) {
        if (watermarkText == null || watermarkText.isEmpty()) {
            return;
        }

        // 水印默认灰色
        String watermarkColor = color != null && !color.isEmpty() ? color : "#CCCCCC";
        
        // 去掉#号
        if (watermarkColor.startsWith("#")) {
            watermarkColor = watermarkColor.substring(1);
        }

        try {
            // 简化版水印实现
            // 创建水印为一个段落
            XWPFParagraph watermarkParagraph = document.createParagraph();
            watermarkParagraph.setAlignment(ParagraphAlignment.CENTER);
            
            XWPFRun run = watermarkParagraph.createRun();
            run.setText(watermarkText);
            run.setFontSize(72); // 大字体
            run.setColor(watermarkColor);
            run.setBold(true);
            
            // 使用文本框作为水印
            CTR ctr = run.getCTR();
            
            // 设置半透明
            ctr.addNewRPr().addNewShd().setFill(watermarkColor);
            ctr.addNewRPr().addNewShd().setVal(STShd.CLEAR);
        } catch (Exception e) {
            log.error("添加水印失败", e);
        }
    }

    /**
     * 添加图片
     *
     * @param paragraph 段落
     * @param imagePath 图片路径
     * @param width 宽度（厘米）
     * @param height 高度（厘米）
     */
    public static void addImage(XWPFParagraph paragraph, String imagePath, double width, double height) {
        try (FileInputStream fis = new FileInputStream(imagePath)) {
            XWPFRun run = paragraph.createRun();
            run.addPicture(
                fis, 
                getPictureType(imagePath), 
                imagePath, 
                Units.toEMU(width), 
                Units.toEMU(height)
            );
        } catch (Exception e) {
            log.error("添加图片失败: " + imagePath, e);
        }
    }

    /**
     * 根据文件扩展名获取图片类型
     *
     * @param imagePath 图片路径
     * @return 图片类型
     */
    private static int getPictureType(String imagePath) {
        String ext = imagePath.substring(imagePath.lastIndexOf(".") + 1).toLowerCase();
        switch (ext) {
            case "png":
                return XWPFDocument.PICTURE_TYPE_PNG;
            case "jpg":
            case "jpeg":
                return XWPFDocument.PICTURE_TYPE_JPEG;
            case "gif":
                return XWPFDocument.PICTURE_TYPE_GIF;
            case "bmp":
                return XWPFDocument.PICTURE_TYPE_BMP;
            default:
                return XWPFDocument.PICTURE_TYPE_JPEG;
        }
    }

    /**
     * 将Word文档转换为PDF
     * 优先使用documents4j，如果失败则尝试LibreOffice，OpenOffice，然后是MS Office
     *
     * @param wordInputStream Word文档输入流
     * @param pdfOutputStream PDF输出流
     * @return 转换是否成功
     */
    public static boolean convertWordToPdf(InputStream wordInputStream, OutputStream pdfOutputStream) {
        log.info("开始转换Word文档到PDF");
        
        try {
            // 首先尝试使用documents4j
            log.info("尝试使用documents4j转换");
            if (convertUsingDocuments4j(wordInputStream, pdfOutputStream)) {
                log.info("使用documents4j转换成功");
                return true;
            }
            
            // 创建可重复使用的输入流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = wordInputStream.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            byte[] byteArray = baos.toByteArray();
            
            // 尝试使用LibreOffice
            log.info("尝试使用LibreOffice转换");
            try (ByteArrayInputStream bais = new ByteArrayInputStream(byteArray)) {
                if (convertUsingLibreOffice(bais, pdfOutputStream)) {
                    log.info("使用LibreOffice转换成功");
                    return true;
                }
            }
            
            // 尝试使用OpenOffice
            log.info("尝试使用OpenOffice转换");
            try (ByteArrayInputStream bais = new ByteArrayInputStream(byteArray)) {
                if (convertUsingOpenOffice(bais, pdfOutputStream)) {
                    log.info("使用OpenOffice转换成功");
                    return true;
                }
            }
            
            // 尝试使用MS Office (仅限Windows系统)
            log.info("尝试使用MS Office转换");
            try (ByteArrayInputStream bais = new ByteArrayInputStream(byteArray)) {
                if (convertUsingMSOffice(bais, pdfOutputStream)) {
                    log.info("使用MS Office转换成功");
                    return true;
                }
            }
            
            log.warn("所有转换方法均失败，转换未成功完成");
            return false;
        } catch (Exception e) {
            log.error("Word转PDF失败", e);
            return false;
        }
    }
    
    /**
     * 使用documents4j进行文档转换
     * 这是一个更可靠的基于MS Office的转换方法
     */
    private static boolean convertUsingDocuments4j(InputStream wordInputStream, OutputStream pdfOutputStream) {
        log.info("使用documents4j进行Word到PDF的转换");
        
        // 仅在Windows系统上尝试，documents4j依赖于MS Office
        String osName = System.getProperty("os.name").toLowerCase();
        if (!osName.contains("win")) {
            log.info("非Windows系统，跳过documents4j转换尝试");
            return false;
        }
        
        // 创建临时文件以避免流操作问题
        File tempInput = null;
        IConverter converter = null;
        
        try {
            // 创建临时输入文件
            tempInput = File.createTempFile("documents4j_input_", ".docx");
            
            // 将输入流写入临时文件
            try (FileOutputStream fos = new FileOutputStream(tempInput)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = wordInputStream.read(buffer)) > 0) {
                    fos.write(buffer, 0, length);
                }
            }
            
            // 使用documents4j进行转换
            converter = LocalConverter.builder()
                .baseFolder(new File(System.getProperty("java.io.tmpdir")))
                .workerPool(1, 1, 60, TimeUnit.SECONDS)
                .processTimeout(60, TimeUnit.SECONDS)
                .build();
            
            boolean result = converter.convert(tempInput)
                .as(DocumentType.DOCX)
                .to(pdfOutputStream)
                .as(DocumentType.PDF)
                .execute();
            
            if (!result) {
                log.error("documents4j转换失败");
                return false;
            }
            
            return true;
        } catch (Exception e) {
            log.error("documents4j转换异常", e);
            return false;
        } finally {
            // 清理临时文件
            if (tempInput != null && tempInput.exists()) {
                tempInput.delete();
            }
            
            // 关闭转换器
            if (converter != null) {
                try {
                    converter.shutDown();
                } catch (Exception e) {
                    log.warn("关闭转换器时发生异常", e);
                }
            }
        }
    }
    
    /**
     * 使用LibreOffice进行文档转换
     */
    private static boolean convertUsingLibreOffice(InputStream wordInputStream, OutputStream pdfOutputStream) throws IOException {
        File tempInput = null;
        File tempOutput = null;
        
        try {
            // 创建临时文件
            tempInput = File.createTempFile("libreoffice_input_", ".docx");
            tempOutput = File.createTempFile("libreoffice_output_", ".pdf");
            
            // 将输入流写入临时文件
            try (FileOutputStream fos = new FileOutputStream(tempInput)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = wordInputStream.read(buffer)) > 0) {
                    fos.write(buffer, 0, length);
                }
            }
            
            // 构建LibreOffice命令
            String osName = System.getProperty("os.name").toLowerCase();
            String[] command;
            
            if (osName.contains("win")) {
                // Windows系统，尝试常见安装路径
                String[] possiblePaths = {
                    "C:\\Program Files\\LibreOffice\\program\\soffice.exe",
                    "C:\\Program Files (x86)\\LibreOffice\\program\\soffice.exe"
                };
                
                String libreofficePath = null;
                for (String path : possiblePaths) {
                    if (new File(path).exists()) {
                        libreofficePath = path;
                        break;
                    }
                }
                
                if (libreofficePath == null) {
                    log.error("LibreOffice未安装或未找到");
                    return false;
                }
                
                command = new String[] {
                    libreofficePath,
                    "--headless",
                    "--convert-to", "pdf",
                    "--outdir", tempOutput.getParent(),
                    tempInput.getAbsolutePath()
                };
            } else {
                // Linux/Mac系统
                command = new String[] {
                    "libreoffice",
                    "--headless",
                    "--convert-to", "pdf",
                    "--outdir", tempOutput.getParent(),
                    tempInput.getAbsolutePath()
                };
            }
            
            // 执行命令
            Process process = Runtime.getRuntime().exec(command);
            int exitCode = process.waitFor();
            
            if (exitCode != 0) {
                log.error("LibreOffice转换失败，退出码: " + exitCode);
                return false;
            }
            
            // 生成的PDF文件名会与输入文件名相同，但扩展名为.pdf
            String pdfFileName = tempInput.getName().replaceFirst("\\.docx$", ".pdf");
            File pdfFile = new File(tempOutput.getParent(), pdfFileName);
            
            if (!pdfFile.exists()) {
                log.error("LibreOffice未生成PDF文件");
                return false;
            }
            
            // 将生成的PDF写入输出流
            try (FileInputStream fis = new FileInputStream(pdfFile)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = fis.read(buffer)) > 0) {
                    pdfOutputStream.write(buffer, 0, length);
                }
            }
            
            return true;
            
        } catch (Exception e) {
            log.error("LibreOffice转换异常", e);
            return false;
        } finally {
            // 清理临时文件
            if (tempInput != null && tempInput.exists()) {
                tempInput.delete();
            }
            if (tempOutput != null && tempOutput.exists()) {
                tempOutput.delete();
            }
        }
    }
    
    /**
     * 使用OpenOffice进行文档转换
     */
    private static boolean convertUsingOpenOffice(InputStream wordInputStream, OutputStream pdfOutputStream) throws IOException {
        File tempInput = null;
        File tempOutput = null;
        
        try {
            // 创建临时文件
            tempInput = File.createTempFile("openoffice_input_", ".docx");
            tempOutput = File.createTempFile("openoffice_output_", ".pdf");
            
            // 将输入流写入临时文件
            try (FileOutputStream fos = new FileOutputStream(tempInput)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = wordInputStream.read(buffer)) > 0) {
                    fos.write(buffer, 0, length);
                }
            }
            
            // 构建OpenOffice命令
            String osName = System.getProperty("os.name").toLowerCase();
            String[] command;
            
            if (osName.contains("win")) {
                // Windows系统，尝试常见安装路径
                String[] possiblePaths = {
                    "C:\\Program Files\\OpenOffice 4\\program\\soffice.exe",
                    "C:\\Program Files (x86)\\OpenOffice 4\\program\\soffice.exe",
                    "C:\\Program Files\\OpenOffice.org 4\\program\\soffice.exe",
                    "C:\\Program Files (x86)\\OpenOffice.org 4\\program\\soffice.exe"
                };
                
                String openofficePath = null;
                for (String path : possiblePaths) {
                    if (new File(path).exists()) {
                        openofficePath = path;
                        break;
                    }
                }
                
                if (openofficePath == null) {
                    log.error("OpenOffice未安装或未找到");
                    return false;
                }
                
                command = new String[] {
                    openofficePath,
                    "--headless",
                    "--convert-to", "pdf",
                    "--outdir", tempOutput.getParent(),
                    tempInput.getAbsolutePath()
                };
            } else {
                // Linux/Mac系统
                command = new String[] {
                    "soffice",
                    "--headless",
                    "--convert-to", "pdf",
                    "--outdir", tempOutput.getParent(),
                    tempInput.getAbsolutePath()
                };
            }
            
            // 执行命令
            Process process = Runtime.getRuntime().exec(command);
            int exitCode = process.waitFor();
            
            if (exitCode != 0) {
                log.error("OpenOffice转换失败，退出码: " + exitCode);
                return false;
            }
            
            // 生成的PDF文件名会与输入文件名相同，但扩展名为.pdf
            String pdfFileName = tempInput.getName().replaceFirst("\\.docx$", ".pdf");
            File pdfFile = new File(tempOutput.getParent(), pdfFileName);
            
            if (!pdfFile.exists()) {
                log.error("OpenOffice未生成PDF文件");
                return false;
            }
            
            // 将生成的PDF写入输出流
            try (FileInputStream fis = new FileInputStream(pdfFile)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = fis.read(buffer)) > 0) {
                    pdfOutputStream.write(buffer, 0, length);
                }
            }
            
            return true;
            
        } catch (Exception e) {
            log.error("OpenOffice转换异常", e);
            return false;
        } finally {
            // 清理临时文件
            if (tempInput != null && tempInput.exists()) {
                tempInput.delete();
            }
            if (tempOutput != null && tempOutput.exists()) {
                tempOutput.delete();
            }
        }
    }
    
    /**
     * 使用Microsoft Office进行文档转换
     */
    private static boolean convertUsingMSOffice(InputStream wordInputStream, OutputStream pdfOutputStream) throws IOException {
        // 仅在Windows系统上尝试
        String osName = System.getProperty("os.name").toLowerCase();
        if (!osName.contains("win")) {
            log.info("非Windows系统，跳过MS Office转换尝试");
            return false;
        }
        
        File tempInput = null;
        File tempOutput = null;
        
        try {
            // 创建临时文件
            tempInput = File.createTempFile("msoffice_input_", ".docx");
            tempOutput = File.createTempFile("msoffice_output_", ".pdf");
            
            // 将输入流写入临时文件
            try (FileOutputStream fos = new FileOutputStream(tempInput)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = wordInputStream.read(buffer)) > 0) {
                    fos.write(buffer, 0, length);
                }
            }
            
            // 构建VBS脚本路径
            File vbsFile = File.createTempFile("convert_", ".vbs");
            
            // 写入VBS脚本内容
            try (FileWriter writer = new FileWriter(vbsFile)) {
                writer.write("Dim wordApp\n");
                writer.write("Dim doc\n");
                writer.write("Dim inputFile\n");
                writer.write("Dim outputFile\n");
                writer.write("inputFile = \"" + tempInput.getAbsolutePath().replace("\\", "\\\\") + "\"\n");
                writer.write("outputFile = \"" + tempOutput.getAbsolutePath().replace("\\", "\\\\") + "\"\n");
                writer.write("On Error Resume Next\n");
                writer.write("Set wordApp = CreateObject(\"Word.Application\")\n");
                writer.write("If Err.Number <> 0 Then\n");
                writer.write("    WScript.Echo \"Error: Microsoft Word not installed\"\n");
                writer.write("    WScript.Quit 1\n");
                writer.write("End If\n");
                writer.write("wordApp.Visible = False\n");
                writer.write("Set doc = wordApp.Documents.Open(inputFile)\n");
                writer.write("If Err.Number <> 0 Then\n");
                writer.write("    WScript.Echo \"Error opening file: \" & Err.Description\n");
                writer.write("    wordApp.Quit\n");
                writer.write("    WScript.Quit 1\n");
                writer.write("End If\n");
                writer.write("doc.SaveAs outputFile, 17 ' 17 = PDF format\n");
                writer.write("If Err.Number <> 0 Then\n");
                writer.write("    WScript.Echo \"Error saving as PDF: \" & Err.Description\n");
                writer.write("    doc.Close False\n");
                writer.write("    wordApp.Quit\n");
                writer.write("    WScript.Quit 1\n");
                writer.write("End If\n");
                writer.write("doc.Close False\n");
                writer.write("wordApp.Quit\n");
                writer.write("WScript.Echo \"Conversion successful\"\n");
                writer.write("WScript.Quit 0\n");
            }
            
            // 执行VBS脚本
            Process process = Runtime.getRuntime().exec(new String[] {
                "cscript.exe", 
                "//NoLogo", 
                vbsFile.getAbsolutePath()
            });
            
            // 等待进程完成
            int exitCode = process.waitFor();
            
            // 清理VBS文件
            vbsFile.delete();
            
            if (exitCode != 0) {
                log.error("MS Office转换失败，退出码: " + exitCode);
                return false;
            }
            
            // 检查输出文件是否存在
            if (!tempOutput.exists() || tempOutput.length() == 0) {
                log.error("MS Office未能生成有效的PDF文件");
                return false;
            }
            
            // 将生成的PDF写入输出流
            try (FileInputStream fis = new FileInputStream(tempOutput)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = fis.read(buffer)) > 0) {
                    pdfOutputStream.write(buffer, 0, length);
                }
            }
            
            return true;
            
        } catch (Exception e) {
            log.error("MS Office转换异常", e);
            return false;
        } finally {
            // 清理临时文件
            if (tempInput != null && tempInput.exists()) {
                tempInput.delete();
            }
            if (tempOutput != null && tempOutput.exists()) {
                tempOutput.delete();
            }
        }
    }
}